
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
// 
//   http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
// 
//   http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
import { SERIES_LAYOUT_BY_COLUMN, SOURCE_FORMAT_OBJECT_ROWS, SOURCE_FORMAT_ARRAY_ROWS } from '../../util/types.js';
import { normalizeToArray } from '../../util/model.js';
import { createHashMap, bind, each, hasOwn, map, clone, isObject, extend, isNumber } from 'zrender/lib/core/util.js';
import { getRawSourceItemGetter, getRawSourceDataCounter, getRawSourceValueGetter } from './dataProvider.js';
import { parseDataValue } from './dataValueHelper.js';
import { log, makePrintable, throwError } from '../../util/log.js';
import { createSource, detectSourceFormat } from '../Source.js';
/**
 * TODO: disable writable.
 * This structure will be exposed to users.
 */

var ExternalSource =
/** @class */
function () {
	function ExternalSource() {}

	ExternalSource.prototype.getRawData = function () {
		// Only built-in transform available.
		throw new Error('not supported');
	};

	ExternalSource.prototype.getRawDataItem = function (dataIndex) {
		// Only built-in transform available.
		throw new Error('not supported');
	};

	ExternalSource.prototype.cloneRawData = function () {
		return;
	};
	/**
   * @return If dimension not found, return null/undefined.
   */

	ExternalSource.prototype.getDimensionInfo = function (dim) {
		return;
	};
	/**
   * dimensions defined if and only if either:
   * (a) dataset.dimensions are declared.
   * (b) dataset data include dimensions definitions in data (detected or via specified `sourceHeader`).
   * If dimensions are defined, `dimensionInfoAll` is corresponding to
   * the defined dimensions.
   * Otherwise, `dimensionInfoAll` is determined by data columns.
   * @return Always return an array (even empty array).
   */

	ExternalSource.prototype.cloneAllDimensionInfo = function () {
		return;
	};

	ExternalSource.prototype.count = function () {
		return;
	};
	/**
   * Only support by dimension index.
   * No need to support by dimension name in transform function,
   * because transform function is not case-specific, no need to use name literally.
   */

	ExternalSource.prototype.retrieveValue = function (dataIndex, dimIndex) {
		return;
	};

	ExternalSource.prototype.retrieveValueFromItem = function (dataItem, dimIndex) {
		return;
	};

	ExternalSource.prototype.convertValue = function (rawVal, dimInfo) {
		return parseDataValue(rawVal, dimInfo);
	};

	return ExternalSource;
}();

export { ExternalSource };

function createExternalSource(internalSource, externalTransform) {
	var extSource = new ExternalSource();
	var data = internalSource.data;
	var sourceFormat = extSource.sourceFormat = internalSource.sourceFormat;
	var sourceHeaderCount = internalSource.startIndex;
	var errMsg = '';

	if (internalSource.seriesLayoutBy !== SERIES_LAYOUT_BY_COLUMN) {
		// For the logic simplicity in transformer, only 'culumn' is
		// supported in data transform. Otherwise, the `dimensionsDefine`
		// might be detected by 'row', which probably confuses users.
		if (process.env.NODE_ENV !== 'production') {
			errMsg = '`seriesLayoutBy` of upstream dataset can only be "column" in data transform.';
		}

		throwError(errMsg);
	} // [MEMO]
	// Create a new dimensions structure for exposing.
	// Do not expose all dimension info to users directly.
	// Because the dimension is probably auto detected from data and not might reliable.
	// Should not lead the transformers to think that is reliable and return it.
	// See [DIMENSION_INHERIT_RULE] in `sourceManager.ts`.

	var dimensions = [];
	var dimsByName = {};
	var dimsDef = internalSource.dimensionsDefine;

	if (dimsDef) {
		each(dimsDef, function (dimDef, idx) {
			var name = dimDef.name;
			var dimDefExt = {
				index: idx,
				name: name,
				displayName: dimDef.displayName
			};
			dimensions.push(dimDefExt); // Users probably do not specify dimension name. For simplicity, data transform
			// does not generate dimension name.

			if (name != null) {
				// Dimension name should not be duplicated.
				// For simplicity, data transform forbids name duplication, do not generate
				// new name like module `completeDimensions.ts` did, but just tell users.
				var errMsg_1 = '';

				if (hasOwn(dimsByName, name)) {
					if (process.env.NODE_ENV !== 'production') {
						errMsg_1 = 'dimension name "' + name + '" duplicated.';
					}

					throwError(errMsg_1);
				}

				dimsByName[name] = dimDefExt;
			}
		});
	} // If dimension definitions are not defined and can not be detected.
	// e.g., pure data `[[11, 22], ...]`.
	else {
		for (var i = 0; i < internalSource.dimensionsDetectedCount || 0; i++) {
			// Do not generete name or anything others. The consequence process in
			// `transform` or `series` probably have there own name generation strategry.
			dimensions.push({
				index: i
			});
		}
	} // Implement public methods:

	var rawItemGetter = getRawSourceItemGetter(sourceFormat, SERIES_LAYOUT_BY_COLUMN);

	if (externalTransform.__isBuiltIn) {
		extSource.getRawDataItem = function (dataIndex) {
			return rawItemGetter(data, sourceHeaderCount, dimensions, dataIndex);
		};

		extSource.getRawData = bind(getRawData, null, internalSource);
	}

	extSource.cloneRawData = bind(cloneRawData, null, internalSource);
	var rawCounter = getRawSourceDataCounter(sourceFormat, SERIES_LAYOUT_BY_COLUMN);
	extSource.count = bind(rawCounter, null, data, sourceHeaderCount, dimensions);
	var rawValueGetter = getRawSourceValueGetter(sourceFormat);

	extSource.retrieveValue = function (dataIndex, dimIndex) {
		var rawItem = rawItemGetter(data, sourceHeaderCount, dimensions, dataIndex);
		return retrieveValueFromItem(rawItem, dimIndex);
	};

	var retrieveValueFromItem = extSource.retrieveValueFromItem = function (dataItem, dimIndex) {
		if (dataItem == null) {
			return;
		}

		var dimDef = dimensions[dimIndex]; // When `dimIndex` is `null`, `rawValueGetter` return the whole item.

		if (dimDef) {
			return rawValueGetter(dataItem, dimIndex, dimDef.name);
		}
	};

	extSource.getDimensionInfo = bind(getDimensionInfo, null, dimensions, dimsByName);
	extSource.cloneAllDimensionInfo = bind(cloneAllDimensionInfo, null, dimensions);
	return extSource;
}

function getRawData(upstream) {
	var sourceFormat = upstream.sourceFormat;

	if (!isSupportedSourceFormat(sourceFormat)) {
		var errMsg = '';

		if (process.env.NODE_ENV !== 'production') {
			errMsg = '`getRawData` is not supported in source format ' + sourceFormat;
		}

		throwError(errMsg);
	}

	return upstream.data;
}

function cloneRawData(upstream) {
	var sourceFormat = upstream.sourceFormat;
	var data = upstream.data;

	if (!isSupportedSourceFormat(sourceFormat)) {
		var errMsg = '';

		if (process.env.NODE_ENV !== 'production') {
			errMsg = '`cloneRawData` is not supported in source format ' + sourceFormat;
		}

		throwError(errMsg);
	}

	if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {
		var result = [];

		for (var i = 0, len = data.length; i < len; i++) {
			// Not strictly clone for performance
			result.push(data[i].slice());
		}

		return result;
	} else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {
		var result = [];

		for (var i = 0, len = data.length; i < len; i++) {
			// Not strictly clone for performance
			result.push(extend({}, data[i]));
		}

		return result;
	}
}

function getDimensionInfo(dimensions, dimsByName, dim) {
	if (dim == null) {
		return;
	} // Keep the same logic as `List::getDimension` did.

	if (isNumber(dim) // If being a number-like string but not being defined a dimension name.
  || !isNaN(dim) && !hasOwn(dimsByName, dim)) {
		return dimensions[dim];
	} else if (hasOwn(dimsByName, dim)) {
		return dimsByName[dim];
	}
}

function cloneAllDimensionInfo(dimensions) {
	return clone(dimensions);
}

var externalTransformMap = createHashMap();
export function registerExternalTransform(externalTransform) {
	externalTransform = clone(externalTransform);
	var type = externalTransform.type;
	var errMsg = '';

	if (!type) {
		if (process.env.NODE_ENV !== 'production') {
			errMsg = 'Must have a `type` when `registerTransform`.';
		}

		throwError(errMsg);
	}

	var typeParsed = type.split(':');

	if (typeParsed.length !== 2) {
		if (process.env.NODE_ENV !== 'production') {
			errMsg = 'Name must include namespace like "ns:regression".';
		}

		throwError(errMsg);
	} // Namespace 'echarts:xxx' is official namespace, where the transforms should
	// be called directly via 'xxx' rather than 'echarts:xxx'.

	var isBuiltIn = false;

	if (typeParsed[0] === 'echarts') {
		type = typeParsed[1];
		isBuiltIn = true;
	}

	externalTransform.__isBuiltIn = isBuiltIn;
	externalTransformMap.set(type, externalTransform);
}
export function applyDataTransform(rawTransOption, sourceList, infoForPrint) {
	var pipedTransOption = normalizeToArray(rawTransOption);
	var pipeLen = pipedTransOption.length;
	var errMsg = '';

	if (!pipeLen) {
		if (process.env.NODE_ENV !== 'production') {
			errMsg = 'If `transform` declared, it should at least contain one transform.';
		}

		throwError(errMsg);
	}

	for (var i = 0, len = pipeLen; i < len; i++) {
		var transOption = pipedTransOption[i];
		sourceList = applySingleDataTransform(transOption, sourceList, infoForPrint, pipeLen === 1 ? null : i); // piped transform only support single input, except the fist one.
		// piped transform only support single output, except the last one.

		if (i !== len - 1) {
			sourceList.length = Math.max(sourceList.length, 1);
		}
	}

	return sourceList;
}

function applySingleDataTransform(transOption, upSourceList, infoForPrint, // If `pipeIndex` is null/undefined, no piped transform.
	pipeIndex) {
	var errMsg = '';

	if (!upSourceList.length) {
		if (process.env.NODE_ENV !== 'production') {
			errMsg = 'Must have at least one upstream dataset.';
		}

		throwError(errMsg);
	}

	if (!isObject(transOption)) {
		if (process.env.NODE_ENV !== 'production') {
			errMsg = 'transform declaration must be an object rather than ' + typeof transOption + '.';
		}

		throwError(errMsg);
	}

	var transType = transOption.type;
	var externalTransform = externalTransformMap.get(transType);

	if (!externalTransform) {
		if (process.env.NODE_ENV !== 'production') {
			errMsg = 'Can not find transform on type "' + transType + '".';
		}

		throwError(errMsg);
	} // Prepare source

	var extUpSourceList = map(upSourceList, function (upSource) {
		return createExternalSource(upSource, externalTransform);
	});
	var resultList = normalizeToArray(externalTransform.transform({
		upstream: extUpSourceList[0],
		upstreamList: extUpSourceList,
		config: clone(transOption.config)
	}));

	if (process.env.NODE_ENV !== 'production') {
		if (transOption.print) {
			var printStrArr = map(resultList, function (extSource) {
				var pipeIndexStr = pipeIndex != null ? ' === pipe index: ' + pipeIndex : '';
				return ['=== dataset index: ' + infoForPrint.datasetIndex + pipeIndexStr + ' ===', '- transform result data:', makePrintable(extSource.data), '- transform result dimensions:', makePrintable(extSource.dimensions)].join('\n');
			}).join('\n');
			log(printStrArr);
		}
	}

	return map(resultList, function (result, resultIndex) {
		var errMsg = '';

		if (!isObject(result)) {
			if (process.env.NODE_ENV !== 'production') {
				errMsg = 'A transform should not return some empty results.';
			}

			throwError(errMsg);
		}

		if (!result.data) {
			if (process.env.NODE_ENV !== 'production') {
				errMsg = 'Transform result data should be not be null or undefined';
			}

			throwError(errMsg);
		}

		var sourceFormat = detectSourceFormat(result.data);

		if (!isSupportedSourceFormat(sourceFormat)) {
			if (process.env.NODE_ENV !== 'production') {
				errMsg = 'Transform result data should be array rows or object rows.';
			}

			throwError(errMsg);
		}

		var resultMetaRawOption;
		var firstUpSource = upSourceList[0];
		/**
     * Intuitively, the end users known the content of the original `dataset.source`,
     * calucating the transform result in mind.
     * Suppose the original `dataset.source` is:
     * ```js
     * [
     *     ['product', '2012', '2013', '2014', '2015'],
     *     ['AAA', 41.1, 30.4, 65.1, 53.3],
     *     ['BBB', 86.5, 92.1, 85.7, 83.1],
     *     ['CCC', 24.1, 67.2, 79.5, 86.4]
     * ]
     * ```
     * The dimension info have to be detected from the source data.
     * Some of the transformers (like filter, sort) will follow the dimension info
     * of upstream, while others use new dimensions (like aggregate).
     * Transformer can output a field `dimensions` to define the its own output dimensions.
     * We also allow transformers to ignore the output `dimensions` field, and
     * inherit the upstream dimensions definition. It can reduce the burden of handling
     * dimensions in transformers.
     *
     * See also [DIMENSION_INHERIT_RULE] in `sourceManager.ts`.
     */

		if (firstUpSource && resultIndex === 0 // If transformer returns `dimensions`, it means that the transformer has different
    // dimensions definitions. We do not inherit anything from upstream.
    && !result.dimensions) {
			var startIndex = firstUpSource.startIndex; // We copy the header of upstream to the result, because:
			// (1) The returned data always does not contain header line and can not be used
			// as dimension-detection. In this case we can not use "detected dimensions" of
			// upstream directly, because it might be detected based on different `seriesLayoutBy`.
			// (2) We should support that the series read the upstream source in `seriesLayoutBy: 'row'`.
			// So the original detected header should be add to the result, otherwise they can not be read.

			if (startIndex) {
				result.data = firstUpSource.data.slice(0, startIndex).concat(result.data);
			}

			resultMetaRawOption = {
				seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN,
				sourceHeader: startIndex,
				dimensions: firstUpSource.metaRawOption.dimensions
			};
		} else {
			resultMetaRawOption = {
				seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN,
				sourceHeader: 0,
				dimensions: result.dimensions
			};
		}

		return createSource(result.data, resultMetaRawOption, null);
	});
}

function isSupportedSourceFormat(sourceFormat) {
	return sourceFormat === SOURCE_FORMAT_ARRAY_ROWS || sourceFormat === SOURCE_FORMAT_OBJECT_ROWS;
}